/* 可持久化数据结构
    (1)trie的可持久化 01区分左右子树
    (2)线段树的可持久化——主席树

* 1.可持久化的前提:本身的拓扑结构不变

* 2.解决什么问题:可以存下来数据结构的所有历史版本
    每一棵树, 都是复制一份前一棵树然后再插入一个当前的ai一共会保存n个bst
    可持久化线段树（主席树）的核心思想是在每次插入新元素时，不会完全重建整棵线段树，而是复用大部分未改变的节点
    只创建新插入元素所影响的路径上的节点。这样可以保存线段树的所有历史版本，每个版本对应一个不同的根节点

* 3.可持久化线段树难以进行区间修改操作

* 本题:
    在数值上建立线段树，维护每个数值区间中一共有多少个数
*/

// #define ONLINE_DUDGE
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
// #define int long long
const int N = 1e5+10, M = 1e4+10;
int n, m, len, A[N];
vector<int> nums; //值域较大，需离散化
int root[N], idx; 

//线段树的每个点
struct SegTree{
    int l, r; //左右子树节点编号
    int cnt; //区间个数
}tree[N * 21]; //N*4 + NlogN

void PrintTree()
{
    for(int i = 0; i < nums.size(); i++)
        printf("tree[%d]: l:%d r:%d cnt:%d\n", i, tree[i].l, tree[i].r, tree[i].cnt);
}

int find(int x) {return lower_bound(nums.begin(), nums.end(), x) - nums.begin();}

int build(int l, int r)
{
    int p = ++idx;
    if(l == r) return p;
    int mid = (l+r) >> 1;

    tree[p].l = build(l, mid); 
    tree[p].r = build(mid+1, r);
    return p;
}

int insert(int p, int l, int r, int x) // root [l, r] 离散化位置
{
    int q = ++idx; //新开辟一个节点
    tree[q] = tree[p]; // 复制根节点
    if(l == r) {tree[q].cnt++; return q;} //叶子节点

    int mid = l + r >> 1;
    if(x <= mid) tree[q].l = insert(tree[p].l, l, mid, x); // 插入位置在左子树
    else tree[q].r = insert(tree[p].r, mid+1, r, x); // 插入位置在左子树
    tree[q].cnt = tree[tree[q].l].cnt + tree[tree[q].r].cnt; //push_up
    return q;

}

int query(int q, int p, int l, int r, int k)
{
    if(l == r) return r;

    //在p之后(即q)，有多少个数插入到左子树中,即[p, q]之间的个数
    //即cnt=存在q左子树但不存在[1.l]中数的个数
    int cnt = tree[tree[q].l].cnt - tree[tree[p].l].cnt;

    int mid = l + r >> 1;
    if(k <= cnt) return query(tree[q].l, tree[p].l, l, mid, k);
    else return query(tree[q].r, tree[p].r, mid+1, r, k-cnt);

}

signed main()
{

    #ifdef ONLINE_JUDGE
    ios::sync_with_stdio(false);   
	cin.tie(0);
    #else
    freopen("./in.txt","r",stdin);
    #endif

    cin >> n >> m;
    
    for(int i = 1; i <= n; i++){
        cin >> A[i];
        nums.push_back(A[i]);
    }

    sort(nums.begin(), nums.end());


    nums.erase(unique(nums.begin(), nums.end()), nums.end());

    root[0] = build(0, nums.size()-1); // 构造树形

    //PrintTree();
    
    for(int i = 1; i <= n; i++)
        root[i] = insert(root[i-1], 0, nums.size()-1, find(A[i]));
    
    while(m--)
    {
        int l, r, k; cin >> l >> r >> k;
        cout << nums[query(root[r], root[l-1], 0, nums.size()-1, k)] << endl;
    }
    
    return 0;
}
